#ifndef CTRL_SELECTION_MODEL_HPP
#define CTRL_SELECTION_MODEL_HPP

#include "Ctrl/CommonCtrlConfig.hpp"
#include <boost/signal.hpp>
#include <set>
#include <list>

namespace Model { class CaseEntity; }

namespace Ctrl
{

/// \ingroup Ctrl
/// \brief It implements the selection of case entities.
///
/// The selection model allows the following operations:<br>
///  \li Replace selection with a list
///  \li Replace selection with one element
///  \li Append element to the selection
///  \li Append list to the selection
///  \li Remove element from the selection
///  \li Remove list from the selection
///  \li Clear selection
///  \li Selection access (iterating through elements).
/// <br>
/// The selection can contain each entity only once. The duplicates are removed while inserting the new entities.
class COMMON_CTRL_API SelectionModel
{
	typedef std::set< Model::CaseEntity*> SelectionCollection;
public:
	/// \brief The iterator types that can be used to access the entities in the selection.
	/// \{
	typedef SelectionCollection::const_iterator ConstSelectionIterator;
	typedef SelectionCollection::iterator SelectionIterator;
	/// \}

	/// \brief It merges the existing selection with the new ones.
	/// \param selected the list of newly selected objects.
	/// 
	/// It removes the duplicates while selecting.<br>
	/// It fires the selection changed signal if the selection was changed (new elements were added to the selection).
	void mergeSelection( const std::list< Model::CaseEntity*>& selected);

	/// \brief It merges the existing selection with the new one.
	/// \param pSelected the new case entity to be added to the selection.
	/// 
	/// If the new entity is already selected, it is not added twice.<br>
	/// It fires the selection changed signal if the selection was changed (new elements were added to the selection).
	void mergeSelection( Model::CaseEntity* pSelected);

	/// \brief It replaces the existing selected objects with the new ones.
	/// \param newSelection the newly selected case entities.
	/// 
	/// If there are duplicates in the new list, they are inserted only once in the selection.<br>
	/// It fires the selection changed signal.
	void replaceSelection( std::list< Model::CaseEntity*>& newSelection);

	/// \brief It replaces the existing selected objects with the new one.
	/// \param pSelected the newly selected entity.<br>
	/// It fires the selection changed signal.
	void replaceSelection( Model::CaseEntity* pSelected);
	
	/// \brief It removes the specified entities from the selection.
	/// \param unselected the list of the case entities to be removed from the selection.
	/// 
	/// In case some entities in the list are not selected, they are ignored.<br>
	/// It fires the selection changed signal if the selection was changed (existing entities were removed from the 
	///	selection).
	void unselect( std::list< Model::CaseEntity*>& unselected);

	/// \brief It removes the specified entity from the selection.
	/// \param pUnselected the case entity to be removed from the selection.
	/// 
	/// In case the entity is not selected, it is ignored.<br>
	/// It fires the selection changed signal if the selection was changed (existing entities were removed from the 
	///	selection).
	void unselect( Model::CaseEntity* pUnselected);

	/// \brief It clears the list of selected entities.
	/// It fires the selection changed signal if the selection was changed (there were entities that were removed.).
	void clear();

	/// \brief It checks whether the selection list is empty.
	bool isEmpty() const;
	
	/// \brief It checks whether the specified entity is selected or not.
	bool isSelected( Model::CaseEntity* pEntityToCheck) const;

	/// \brief It gets the iterator to the beginning of the selection.
	/// \{
	ConstSelectionIterator begin() const { return selection_.begin(); }
	SelectionIterator begin() { return selection_.begin(); }
	/// \}

	/// \brief It gets the iterator to the end of the selection.
	/// \{
	ConstSelectionIterator end() const { return selection_.end(); }
	SelectionIterator end() { return selection_.end(); }
	/// \}
	
	/// \brief It gets the number of entities in the selection.
	std::size_t size() const { return selection_.size(); }

public:
	typedef boost::signal< void (const SelectionModel&)> SelectionChangedSlot;
	/// \brief It connects the selection changed signal to the specified slot.
	void subscribeToSelectionChanged( const SelectionChangedSlot::slot_type& slot);

private:
	SelectionCollection selection_;

private: // Slots
	/// \brief The signal emitted when the selection content changed.
	SelectionChangedSlot onSelectionChanged_;

private:
	/// \brief It inserts a new entity in the selection.
	/// \pre It assumes that the specified element is not existing in the selection.
	/// \pre It assumes that the new entity is not NULL.
	void insert( Model::CaseEntity* pSelected);
};


} // namespace Ctrl

#endif // CTRL_SELECTION_MODEL_HPP